#include <iostream>
#include <signal.h>
#include <mysql.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include "../comm/util.hpp"
#include "../comm/httplib.h"
#include "oj_control.hpp"
#include "oj_view.hpp"

using namespace httplib;
using namespace ns_control;

static Control *ctrl_ptr = nullptr;
void Recovery(int signo)
{
    ctrl_ptr->RecoveryMachines();
}

#define MAX_EVENTS 1024
#define BUFFER_SIZE 4096

struct Connection
{
    int fd;
    std::string read_buf;
    std::string write_buf;
    bool keep_alive;
};

int set_nonblocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

int main()
{
    signal(SIGQUIT, Recovery);
    Control ctrl;
    ctrl_ptr = &ctrl;

    // 创建监听socket
    int listen_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
    if (listen_fd < 0)
    {
        perror("socket");
        return 1;
    }

    // 设置端口复用
    int opt = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 绑定地址
    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8080);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(listen_fd, (sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("bind");
        return 1;
    }

    // 开始监听
    if (listen(listen_fd, SOMAXCONN) < 0)
    {
        perror("listen");
        return 1;
    }

    // 创建epoll实例
    int epoll_fd = epoll_create1(0);
    if (epoll_fd < 0)
    {
        perror("epoll_create1");
        return 1;
    }

    // 添加监听socket到epoll
    epoll_event event{};
    event.events = EPOLLIN | EPOLLET;
    event.data.fd = listen_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event) < 0)
    {
        perror("epoll_ctl");
        return 1;
    }

    // 连接映射表
    std::unordered_map<int, Connection> connections;
    epoll_event events[MAX_EVENTS];

    // 主事件循环
    while (true)
    {
        // wait返回当前已就绪的fd数量
        int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
        if (n < 0)
        {
            perror("epoll_wait");
            continue;
        }

        for (int i = 0; i < n; ++i)
        {
            int fd = events[i].data.fd;

            // 处理新连接
            if (fd == listen_fd)
            {
                while (true)
                {
                    // 监听新连接到来
                    sockaddr_in client_addr{};
                    socklen_t addr_len = sizeof(client_addr);
                    int conn_fd = accept4(listen_fd, (sockaddr *)&client_addr, &addr_len, SOCK_NONBLOCK);
                    if (conn_fd < 0)
                    {
                        if (errno == EAGAIN || errno == EWOULDBLOCK)
                            break;
                        perror("accept4");
                        break;
                    }

                    // 添加新连接到epoll
                    event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
                    event.data.fd = conn_fd;
                    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, conn_fd, &event) < 0)
                    {
                        perror("epoll_ctl");
                        close(conn_fd);
                        continue;
                    }

                    connections[conn_fd] = {conn_fd, "", "", false};
                }
            }
            // 处理连接关闭
            else if (events[i].events & EPOLLRDHUP)
            {
                close(fd);
                connections.erase(fd);
            }
            // 处理可读事件
            else if (events[i].events & EPOLLIN)
            {
                auto &conn = connections[fd];
                char buf[BUFFER_SIZE];

                while (true)
                {
                    ssize_t count = read(fd, buf, sizeof(buf));
                    if (count == -1)
                    {
                        if (errno == EAGAIN || errno == EWOULDBLOCK)
                            break;
                        perror("read failed");
                        close(fd);
                        connections.erase(fd);
                        break;
                    }
                    else if (count == 0)
                    {
                        close(fd);
                        connections.erase(fd);
                        break;
                    }
                    // 不断读取内容，追加至读缓冲区
                    conn.read_buf.append(buf, count);
                }

                // 处理完整HTTP请求
                size_t end_pos;
                while ((end_pos = conn.read_buf.find("\r\n\r\n")) != std::string::npos) // http报文反序列化
                {
                    // 解析请求
                    std::string request = conn.read_buf.substr(0, end_pos + 4);
                    conn.read_buf.erase(0, end_pos + 4);

                    // 创建httplib请求响应对象
                    Request req;
                    Response resp;

                    // 解析HTTP请求
                    size_t start = request.find(' ');
                    size_t end = request.find(' ', start + 1);
                    std::string method = request.substr(0, start);
                    std::string path = request.substr(start + 1, end - start - 1);

                    // 解析路径参数
                    std::smatch match;
                    std::regex question_pattern(R"(/question/(\d+))");
                    std::regex judge_pattern(R"(/judge/(\d+))");

                    // 路由分发
                    if (path == "/all_questions" && method == "GET")
                    {
                        std::string html;
                        ctrl.AllQuestions(&html);
                        resp.set_content(html, "text/html;charset=utf-8");
                    }
                    else if (std::regex_match(path, match, question_pattern) && method == "GET")
                    {
                        std::string number = match[1];
                        std::string html;
                        ctrl.Question(number, &html);
                        resp.set_content(html, "text/html;charset=utf-8");
                    }
                    else if (std::regex_match(path, match, judge_pattern) && method == "POST")
                    {
                        std::string number = match[1];
                        // 获取POST body
                        size_t body_start = request.find("\r\n\r\n");
                        std::string body = request.substr(body_start + 4);
                        std::string result_json;
                        ctrl.Judge(number, body, &result_json);
                        resp.set_content(result_json, "application/json;charset=utf-8");
                    }
                    else
                    {
                        resp.status = 404;
                        resp.set_content("Not Found", "text/plain");
                    }

                    // 序列化生成http响应
                    conn.write_buf += "HTTP/1.1 200 OK\r\n";
                    conn.write_buf += "Content-Type: " + resp.get_header_value("Content-Type") + "\r\n";
                    conn.write_buf += "Content-Length: " + std::to_string(resp.body.size()) + "\r\n";
                    conn.write_buf += "\r\n";
                    conn.write_buf += resp.body;

                    // 修改epoll事件为监听写事件
                    event.events = EPOLLOUT | EPOLLET | EPOLLRDHUP;
                    event.data.fd = fd;
                    epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event);
                }
            }
            // 处理可写事件
            else if (events[i].events & EPOLLOUT)
            {
                auto &conn = connections[fd];

                // 发送响应数据
                ssize_t sent = send(fd, conn.write_buf.data(), conn.write_buf.size(), MSG_NOSIGNAL);
                if (sent < 0)
                {
                    close(fd);
                    connections.erase(fd);
                    continue;
                }

                conn.write_buf.erase(0, sent);

                if (conn.write_buf.empty())
                {
                    // 恢复监听读事件
                    event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
                    event.data.fd = fd;
                    epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fd, &event);

                    // 短连接则关闭
                    if (!conn.keep_alive)
                    {
                        close(fd);
                        connections.erase(fd);
                    }
                }
            }
        }
    }

    close(listen_fd);
    close(epoll_fd);
    return 0;
}
